__asm__(".code16gcc");
//实模式下
#include"boot_info.h"
#include"cpu_instr.h"
#include"loader.h"
static _boot_info_t boot_info;

static void show_msg(const char*msg){
   //内联汇编见文档
   char c;
   while((c=*msg++)!='\0')
   {
      //分配c变量给随机寄存器内
      //编译器不优化我的代码，原封不动
      __asm__ __volatile__(
         "mov $0xe, %%ah\n\t"
	      "mov %[ch], %%al\n\t"
	      "int $0x10\n\t"::[ch]"r"(c)
      );
   }
}
static void detect_memory(void){
   boot_info.ram_region_count=0;
   unit32_t contID=1;
   for(int i=0;contID!=0&&i<BOOT_RAM_REGGIN;i++)
   {
      if(!i)contID=0;//开始contID=0,开始检测，后代表下次检测起始位置
      unit32_t signaure,bytes;

      SMAP_entry_t smap_entry;
      SMAP_entry_t*entry=&smap_entry;
      //eax.ebx,edx,edi
      __asm__ __volatile__ ("int $0x15"
      :"=a"(signaure),
      "=c"(bytes),
      "=b"(contID)
      :"a"(0xE820),
      "b"(contID),
      "c"(24),
      "d"(0x534D4150),"D"(entry)
      );
      if(signaure!=0x534D4150)
         return;
      if(bytes>20&&(entry->ACPI&0x0001)==0)//读取无效标志
         continue;
      if(entry->Type==1){
         //只读低32位，4g,一般每次返回内存块不超过4G，就不读entry的高位了（可优化，先搞明白这内存以后怎么用，再决定记录
         boot_info.ram_region_cfg[boot_info.ram_region_count].start=entry->BaseL;
         boot_info.ram_region_cfg[boot_info.ram_region_count++].size=entry->LengthL;
      }
   }
}

unit16_t gdt_table[][4]={
   [1]={0xFFFF,0X0000,0X9a00,0x00cf},
   [2]={0xFFFF,0X0000,0X9200,0x00cf},
};

static void enter_protect_mode(void){
   //进入保护模式
   //关中断
   cli();
   //读取端口0x92并回写0x2，打开A20地址线
   unit8_t v=inb(0x92);
   outb(0x92,v|0x2);
   //加载gdt表
   lgdt((unit32_t)gdt_table,sizeof(gdt_table));
   //设置cr0寄存器第二位PE（Protection Enable）位，0处理器运行实模式，1保护模式
   unit32_t cr0=read_cr0();
   write_cr0(cr0|(1<<0));
   //远跳指令清空流水线  8?
   far_jump(8,(unit32_t)protect_mode_entry);
   //这里CS已经变为8了，存GDT表的第几位开始
}
void loader_entry(void){
   show_msg("loader_running....\r\n");

   show_msg("loading memory info...\r\n");
   detect_memory();
   show_msg("loading memory info complete\r\n");

   show_msg("entering_protect_mode....\r\n");
   enter_protect_mode();
   
}